package core.api.offer;

import jade.util.Logger;

import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;

import core.datamodel.AccountData;
import core.datamodel.Constants;
import core.datamodel.Element;
import core.datamodel.ElementValue;
import core.datamodel.Resource;
import core.datamodel.ResourceCounter;

public class OfferVirtualMachine {


	private OfferHelper offerModel = null;
	private Logger log = Logger.getJADELogger(this.getClass().getName());
	private boolean flat = false;

	private ArrayList<ElementValue> accountValues = new ArrayList<ElementValue> ();
	private ArrayList<ResourceCounter> accountCounters = new ArrayList<ResourceCounter> ();
	private AccountData account = new AccountData();

	public OfferVirtualMachine(boolean flat){
		this.flat = flat;
	}

	public AccountData calculate(Resource resource, Date startTime,	long interval) {
		log.info("Richiesto il calcolo per VirtualMachine offerta a consumo per il timestamp " + startTime);

		offerModel = new OfferHelper( resource, startTime,interval);

		boolean isVmTemplate = true;
		for (Element ele : resource.getElements()){
			if (ele.getName().equals("CUSTOM")){
				isVmTemplate = false;
				break;
			}
		}

		if (flat){

			if (isVmTemplate) 
				offerFlatWithTemplate(resource, startTime,interval);
			else
				offerFlatCustom(resource, startTime,interval);
		} else {
			if (isVmTemplate) 
				offerUsageWithTemplate(resource, startTime,interval);
			else
				offerUsageCustom(resource, startTime,interval);
		}

		account.setCounters(accountCounters);
		account.setElementValues(accountValues);

		return account;

	}




	public void offerFlatWithTemplate (Resource resource, Date startTime,	long interval){
		log.info("Offerta Flat con template");

		Hashtable<String, Float> templateCosts = new Hashtable<String, Float> ();
		templateCosts.put("Linux Bronze", (float) 90);
		templateCosts.put("Linux Bronze Plus", (float) 140);
		templateCosts.put("Linux Silver", (float) 280);
		templateCosts.put("Linux Silver Plus", (float) 420);
		templateCosts.put("Linux Gold", (float) 560);
		templateCosts.put("Linux Gold Plus", (float) 1120);

		// get  template name
		String templateName = null;
		for (Element ele : resource.getElements()){
			if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_TEMPLATE)){
				templateName = ele.getValue();
				break;
			}
		}

		Float templateCost = templateCosts.get(templateName);

		if (templateCost != null){
			float monthlyCost = templateCost.floatValue();
			System.out.println("Trovato template " + templateName + " costo "+monthlyCost );
			ResourceCounter dayCounter = offerModel.getDayCounter("CHECK_DATE_VMTEMPLATE", flat);

			if ( dayCounter.isNewCounter() | 
					(( (long)((startTime.getTime() / Constants.MILLIS_DAY) )* Constants.MILLIS_DAY) != 
						dayCounter.getLastUpdate().getTime())  ){
				// new day generate account data

				for (Element ele : resource.getElements()){
					System.out.println(ele.getName());

					if (ele.getName().equals(Constants.RESOURCE_COST_ONERI_FISSI) ){
						accountValues.add( offerModel.getElementValue(ele, dayCounter, monthlyCost, true));
					}
				} // end for

				dayCounter.setUpdateCounter(true);
				// set normaliza date
				long time = (long) ((long) ( startTime.getTime()/ Constants.MILLIS_DAY)* Constants.MILLIS_DAY );
				dayCounter.setLastUpdate( new Date(time)  );
				accountCounters.add(dayCounter);
			
			} else {
				log.info("No new day and no account date must be generated for resource name="+resource.getResourceName());
			}
		
		} else {
			log.info("Error no found template name .... calculate offer with no template");
			offerFlatCustom ( resource, startTime,	interval);
		}

	}


	public void offerFlatCustom (Resource  resource, Date startTime,	long interval){
		log.info("Offerta Flat custom");

		float FLAT_CPU_COST_MONTHLY=10;
		float FLAT_MEM_COST_MONTHLY=23;
		float FLAT_DISK_COST_MONTHLY=(float) (40. /250.);
		float FLAT_ONERI_FISSI_MONTHLY=30;


		// flat offer
		ResourceCounter dayCounter = offerModel.getDayCounter("CHECK_DATE", flat);

		if ( dayCounter.isNewCounter() | 
				(( (long)((startTime.getTime() / Constants.MILLIS_DAY) )* Constants.MILLIS_DAY) != 
					dayCounter.getLastUpdate().getTime())  ){
			// new day generate account data

			for (Element ele : resource.getElements()){
				if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_CPU) ){
					accountValues.add( offerModel.getElementValue(ele, dayCounter, FLAT_CPU_COST_MONTHLY, true));
				} else if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_RAM) ){
					accountValues.add( offerModel.getElementValue(ele, dayCounter, FLAT_MEM_COST_MONTHLY, true));
				}else if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_STORAGE) ){
					accountValues.add( offerModel.getElementValue(ele, dayCounter, FLAT_DISK_COST_MONTHLY, true));
				}else if (ele.getName().equals(Constants.RESOURCE_COST_ONERI_FISSI) ){
					accountValues.add( offerModel.getElementValue(ele, dayCounter, FLAT_ONERI_FISSI_MONTHLY, true));
				}
			} // end for

			dayCounter.setUpdateCounter(true);
			// set normaliza date
			long time = (long) ((long) ( startTime.getTime()/ Constants.MILLIS_DAY)* Constants.MILLIS_DAY );
			dayCounter.setLastUpdate( new Date(time)  );
			accountCounters.add(dayCounter);
		} else {
			log.info("No new day and no account date must be generated for resource name="+resource.getResourceName());
		}
	}


	public void offerUsageWithTemplate (Resource resource, Date startTime,	long interval){
		log.info("Offerta Usage con template");

		// usage offer 
		float USAGE_CPU_COST_MONTHLY=13; // 
		float USAGE_MEM_COST_MONTHLY=29;
		float FLAT_DISK_COST_MONTHLY=(float) (40. /250.); // fix 1 time for day
		float FLAT_ONERI_FISSI_MONTHLY=0; // fix 1 1 time for day

		// all interval account data
		for (Element ele : resource.getElements()){
			if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_CPU) ){
				addAccountElementData(ele, startTime,"CPU_DAY_CHARGE",USAGE_CPU_COST_MONTHLY, false);
			} else if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_RAM)){
				addAccountElementData(ele, startTime,"MEM_DAY_CHARGE",USAGE_MEM_COST_MONTHLY, false);
			}

		} // end for element

		// only 1 time per day

		// flat offer
		ResourceCounter dayCounter = offerModel.getDayCounter("CHECK_DATE", true);

		if ( dayCounter.isNewCounter() | 
				(( (long)((startTime.getTime() / Constants.MILLIS_DAY) )* Constants.MILLIS_DAY) != 
					dayCounter.getLastUpdate().getTime())  ){
			// new day generate account data

			for (Element ele : resource.getElements()){

				if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_STORAGE) ){
					accountValues.add( offerModel.getElementValue(ele, dayCounter, FLAT_DISK_COST_MONTHLY, true));

				} else if (ele.getName().equals(Constants.RESOURCE_COST_ONERI_FISSI) ){
					accountValues.add( offerModel.getElementValue(ele, dayCounter,FLAT_ONERI_FISSI_MONTHLY , true));
				} 
			}
			dayCounter.setUpdateCounter(true);
			// set normaliza date
			long time = (long) ((long) ( startTime.getTime()/ Constants.MILLIS_DAY)* Constants.MILLIS_DAY );
			dayCounter.setLastUpdate( new Date(time)  );
			accountCounters.add(dayCounter);
		} 
	}

	public void offerUsageCustom(Resource resource, Date startTime,	long interval){
		// usage offer 
		float USAGE_CPU_COST_MONTHLY=13; // 
		float USAGE_MEM_COST_MONTHLY=29;
		float FLAT_DISK_COST_MONTHLY=(float) (40. /250.); // fix 1 time for day
		float FLAT_ONERI_FISSI_MONTHLY=30; // fix 1 1 time for day

		// all interval account data
		for (Element ele : resource.getElements()){
			if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_CPU) ){
				addAccountElementData(ele, startTime,"CPU_DAY_CHARGE",USAGE_CPU_COST_MONTHLY, false);
			} else if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_RAM)){
				addAccountElementData(ele, startTime,"MEM_DAY_CHARGE",USAGE_MEM_COST_MONTHLY, false);
			}

		} // end for element

		// only 1 time per day
		// flat offer
		ResourceCounter dayCounter = offerModel.getDayCounter("CHECK_DATE", true);

		if ( dayCounter.isNewCounter() | 
				(( (long)((startTime.getTime() / Constants.MILLIS_DAY) )* Constants.MILLIS_DAY) != 
					dayCounter.getLastUpdate().getTime())  ){
			// new day generate account data

			for (Element ele : resource.getElements()){
				if (ele.getName().equals(Constants.VIRTUAL_MACHINE_ELEMENT_STORAGE) ){
					accountValues.add( offerModel.getElementValue(ele, dayCounter, FLAT_DISK_COST_MONTHLY, true));
				} else if (ele.getName().equals(Constants.RESOURCE_COST_ONERI_FISSI) ){
					accountValues.add( offerModel.getElementValue(ele, dayCounter,FLAT_ONERI_FISSI_MONTHLY , true));
				} 
			}
			dayCounter.setUpdateCounter(true);
			// set normaliza date
			long time = (long) ((long) ( startTime.getTime()/ Constants.MILLIS_DAY)* Constants.MILLIS_DAY );
			dayCounter.setLastUpdate( new Date(time)  );
			accountCounters.add(dayCounter);
		} 
	}




	// helper method
	private void addAccountElementData( Element element,Date startTime, String counterDayName, float monthlyPrice, boolean flat){
		// calcolo costo per cpu
		if (element.getUsage() != null){
			// ci sono dati di utilizzo allora posso calcolare
			ResourceCounter dayCounter = offerModel.getDayCounter(counterDayName, flat);
			ElementValue eValue = offerModel.getElementValue(element, dayCounter, monthlyPrice, flat);

			dayCounter.setCounterValue(eValue.getTotalDayCharge());
			dayCounter.setUpdateCounter(true);
			dayCounter.setLastUpdate(startTime);

			accountValues.add(eValue);
			accountCounters.add(dayCounter);
			log.info("Add data e counter for element id="+element.getId());

		} else {
			log.info("No usage data for element id="+element.getId());
		}

	}
}
